package proto

// 目前为了减小消耗长度写的比较死，以后要做通用的话可以统一用 int64，然后做个 slice 做 header

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"log"
)

// 编码协议头定义：
// 文件名长度 1 byte ,不超过 255, uint8
// fileName 实体
// 文件 hash 长度 1 byte ,不超过 255, uint8
// hash 实体
// 文件大小 8 byte , int64
// message 实体

const (
	headerFileNameLength    = 1
	headerHashLength        = 1
	headerFileMessageLength = 8
)

var (
	fileNameLength    uint8
	fileHashLength    uint8
	fileMessageLength int64
)

// Encode 将消息编码
func Encode(fileName, hash, message []byte) ([]byte, error) {
	var pkg = new(bytes.Buffer)

	// 读取文件名的长度，转换成uint类型（占1个字节）
	fileNameLength = uint8(len(fileName))
	// 写入消息头
	if err := binary.Write(pkg, binary.LittleEndian, fileNameLength); err != nil {
		return nil, err
	}
	// 写入文件名实体
	if err := binary.Write(pkg, binary.LittleEndian, fileName); err != nil {
		return nil, err
	}

	// 读取hash的长度，转换成uint类型（占1个字节）,目前使用 md5 作为 hash 函数，因此 hash 为定长 32 位
	fileHashLength = uint8(len(hash))
	// 写入消息头
	if err := binary.Write(pkg, binary.LittleEndian, fileHashLength); err != nil {
		return nil, err
	}
	// 写入文件名实体
	if err := binary.Write(pkg, binary.LittleEndian, hash); err != nil {
		return nil, err
	}

	// 读取消息的长度，转换成int64类型（占8个字节）
	length := int64(len(message))
	// 写入消息头
	if err := binary.Write(pkg, binary.LittleEndian, length); err != nil {
		return nil, err
	}
	// 写入消息实体
	if err := binary.Write(pkg, binary.LittleEndian, message); err != nil {
		return nil, err
	}

	return pkg.Bytes(), nil
}

// Decode 解码消息
func Decode(reader *bufio.Reader) (fileName, hash, message string, err error) {
	// 读取文件名的长度
	lengthByte, _ := reader.Peek(headerFileNameLength) // 读取header
	lengthBuff := bytes.NewBuffer(lengthByte)
	err = binary.Read(lengthBuff, binary.LittleEndian, &fileNameLength)
	log.Println("fileNameLength:", fileNameLength)
	if err != nil {
		return "", "", "", err
	}
	// Buffered返回缓冲中现有的可读取的字节数。
	if reader.Buffered() < int(fileNameLength)+headerFileNameLength {
		return "", "", "", err
	}
	// 读取真正的文件名
	pack1 := make([]byte, int(fileNameLength+headerFileNameLength))
	_, err = reader.Read(pack1)
	if err != nil {
		return "", "", "", err
	}

	// 读取消息的长度
	lengthByte, _ = reader.Peek(headerHashLength) // 读取header
	lengthBuff = bytes.NewBuffer(lengthByte)
	err = binary.Read(lengthBuff, binary.LittleEndian, &fileHashLength)
	log.Println("fileMessageLength:", fileHashLength)
	if err != nil {
		return "", "", "", err
	}
	// Buffered返回缓冲中现有的可读取的字节数。
	if reader.Buffered() < int(fileHashLength+headerHashLength) {
		return "", "", "", err
	}
	// 读取真正的消息数据
	pack2 := make([]byte, int(headerHashLength+fileHashLength))
	_, err = reader.Read(pack2)
	if err != nil {
		return "", "", "", err
	}

	// 读取消息的长度
	lengthByte, _ = reader.Peek(headerFileMessageLength) // 读取header
	lengthBuff = bytes.NewBuffer(lengthByte)
	err = binary.Read(lengthBuff, binary.LittleEndian, &fileMessageLength)
	log.Println("fileMessageLength:", fileMessageLength)
	if err != nil {
		return "", "", "", err
	}
	// Buffered返回缓冲中现有的可读取的字节数。
	if int64(reader.Buffered()) < fileMessageLength+headerFileMessageLength {
		return "", "", "", err
	}
	// 读取真正的消息数据
	pack3 := make([]byte, int(headerFileMessageLength+fileMessageLength))
	_, err = reader.Read(pack3)
	if err != nil {
		return "", "", "", err
	}

	return string(pack1[headerFileNameLength:]), string(pack2[headerHashLength:]), string(pack3[headerFileMessageLength:]), nil
}
